﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Data.SqlTypes;

using Noris.Schedule.Support;
using Noris.Schedule.Support.Data;
using Noris.Schedule.Support.Sql;
using Noris.Schedule.Support.DataFace;
using Noris.Schedule.Support.Services;

using Noris.Schedule.Planning.DataFace;
using System.Drawing;

namespace Noris.Schedule.Planning.ProcessData
{
	// ZÁKLADNÍ a SPOLEČNÉ TŘÍDY, nespecifické pro jednotlivé moduly
	#region CLASS PlanItemCls<P> : předek tříd, které mají Autoincrement ID a mají generickou property Parent
	/// <summary>
	/// PlanItemCls : předek tříd, které mají Autoincrement ID a mají generickou property Parent.
	/// (typu Záznam osy, tasku, průchodu, ...)
	/// </summary>
	/// <typeparam name="P">Datový typ Parenta, který je uložen v property Parent</typeparam>
	public class PlanItemCls<P> : IRecordNumber
	{
		#region KONSTRUKCE
		/// <summary>
		/// Konstruktor: uloží do objektu referenci na svého parenta a přidělí nové ID. První ID = 1.
		/// </summary>
		/// <param name="parent"></param>
		internal PlanItemCls(P parent)
		{
			_Parent = parent;
			this.SetNextID();
		}
		/// <summary>
		/// Konstruktor: uloží do objektu referenci na svého parenta a přidělí nové ID. První ID = 1.
		/// </summary>
		/// <param name="parent">Objekt parenta</param>
		/// <param name="withNoID">Požadavek na potlačení přidělení čísla ID: true = ID bude 0 a čítač ID se nezmění, false = objekt dostane normální platné ID</param>
		internal PlanItemCls(P parent, bool withNoID)
		{
			_Parent = parent;
			if (!withNoID)
				this.SetNextID();
		}
		/// <summary>
		/// Parent prvku, který byl předán do konstruktoru.
		/// </summary>
		internal P Parent { get { return _Parent; } }
		private P _Parent;
		/// <summary>
		/// Metoda vloží nového parenta do tohoto objektu.
		/// Je určeno typicky pro situaci, kdy je objekt vytvořen "bez parenta", a parent se určí až později.
		/// Metoda uvnitř nemá žádné omezení: parenta lze přepsat, vynulovat, cokoli.
		/// </summary>
		/// <remarks>
		/// Nemůžu použít přímo setování propery Parent, protože pro set chci dát přístup jen "protected" (pro potomky, ale ne zvenku),
		/// a přitom Parent musí být "internal" protože generická třída P bývá internal,
		/// ale protože třída jako celek je "public", pak z ní může dědit i něco co není internal, a pak dojde k problému:
		/// The accessibility modifier of the 'Parent.set' accessor must be more restricitve than property 'Parent'.
		/// </remarks>
		/// <param name="parent"></param>
		protected void ParentSet(P parent)
		{ _Parent = parent; }
		/// <summary>
		/// Jednoznačné ID prvku.
		/// První vytvořený prvek má ID = 1.
		/// </summary>
		internal int ItemID { get { return _ItemID; } }
		/// <summary>
		/// Přístup k base proměnné je jen pro potomstvo
		/// </summary>
		protected int _ItemID;
		/// <summary>
		/// Číslo záznamu v databázi (typicky cislo_nonsubjektu).
		/// Přebírá se buď při načítání z databáze, anebo po uložení nové věty do databáze.
		/// </summary>
		public int RecordNumber { get { return _RecordNumber; } internal set { _RecordNumber = value; } }
		/// <summary>
		/// IRecordNumber.RecordNumber : get i set bez omezení
		/// </summary>
		int IRecordNumber.RecordNumber { get { return _RecordNumber; } set { _RecordNumber = value; } }
		private int _RecordNumber;
		/// <summary>
		/// Posledně přidělené ID prvku. Příští prvek bude mít ID o 1 vyšší.
		/// </summary>
		protected static volatile int LastID = 0;
		/// <summary>
		/// Zámek pro thread-safety přidělování nových ID
		/// </summary>
		protected static object LockID = new object();
		#endregion
		#region SERVISNÍ METODY
		/// <summary>
		/// Vygeneruje a do this instance vloží nové ID.
		/// Volá se typicky při klonování potomka, když potomek má mít novou identitu (ale původní data).
		/// </summary>
		protected void SetNextID()
		{
			lock (LockID)
			{
				int itemID = ++LastID;
				if (itemID >= (Int32.MaxValue - 10))
				{	// Pokud bych se blížil MaxValue, začnu znovu od 1:
					// Na osvětlení dodávám: aplikace funguje jednouživatelsky, 
					// po použití se zavře a pak jejím novým spuštěním se inicializují (nulují) statické proměnné,
					//   jako je například LastID.
					// Takže k přetečení (2 miliardy vytvořených ID) při jednom použití nedojde.
					// Plánovací proces vygeneruje jedním chodem maximálně 2 miliony items, 
					//   a nikdo nebude 1000x spouštět proces v jednom okně bez vypnutí.
					// A když by i spustil, pak dojde k nulování LastID (nastaví se zde na 1).
					// Hodnoty ID z dolního rozsahu hodnot (1,2,3,4,5,...) vygenerované (a použité v instancích) před nulováním 
					//   již dávno nemohou nikde v datech existovat. Konflikt nehrozí.
					LastID = 1;
					itemID = 1;
				}
				_ItemID = itemID;
			}
		}
		/// <summary>
		/// Metoda pro uložení obsahu tohoto objektu do databáze.
		/// Určeno k přepsání na potomkovi.
		/// </summary>
		internal virtual void SaveRecord()
		{ }
		/// <summary>
		/// Metoda uloží daný záznam (record) a zajistí vzájemnou synchronizaci klíče záznamu RecordNumber se svým RecordNumber.
		/// Tedy: pokud this obsahuje kladné číslo záznamu RecordNumber, pak jej vepíše do dodaného recordu do jeho RecordNumber.
		/// Pak uloží record (jeho metodou Save()).
		/// Po uložení, pokud v this není uloženo číslo záznamu (tedy když je this.RecordNumber menší nebo 0) 
		/// si do this.RecordNumber načte číslo záznamu z recordu.
		/// Zajistí tedy: pokud v this je známé číslo RecordNumber, pak dodaný záznam bude uložen do tohoto čísla.
		/// Pokud v this.RecordNumber není číslo, pak se record uloží pod jeho číslem RecordNumber (nebo 0 = INSERT),
		/// a do this se opíše reálné výsledné číslo záznamu.
		/// </summary>
		/// <param name="record"></param>
		internal void SaveViaRecord(RecordCls record)
		{
			if (this.RecordNumber > 0)
				((IDbRecord)record).RecordNumber = this.RecordNumber;

			record.Save();

			if (this.RecordNumber <= 0)
				this.RecordNumber = record.RecordNumber;
		}
		/// <summary>
		/// Metoda pro naplnění tohoto objektu daty načtenými z databáze.
		/// Určeno k přepsání na potomkovi.
		/// </summary>
		internal virtual void LoadRecord(IDbRecord source)
		{ }
		/// <summary>
		/// Metoda vynuluje svoji hodnotu RecordNumber.
		/// Virtuální metoda: dovolí rozšířit funkcionalitu pro své potomky, kteří mohou zajistit totéž pro své vnitřní členy.
		/// </summary>
		internal virtual void StoreEmptyRecordNumber()
		{
			this.RecordNumber = 0;
		}
		#endregion
	}
	#endregion
	#region CLASS IndexKCls : jednoduchá podpora pro indexování dat typu 1:N <K, Dictionary<int, T>>
	/// <summary>
	/// IndexIntCls : jednoduchá podpora pro indexování dat typu 1:N &lt;K, Dictionary&lt;int, T&gt;&gt;
	/// Třídou K je klíčový údaj, podle něj se index vytváří
	/// Do indexu se pod konkrétní klíč ukládá soupis: ID věty, reference na větu
	/// </summary>
	/// <typeparam name="K">Třída klíče, podle něj se data seskupují v indexu, podle něj se hledají výsledky. Musí podporovat hashování. (GetHashCode(), Equals())</typeparam>
	/// <typeparam name="T">Třída dat, která se ukládají v indexu. Měla by to být třída (class).</typeparam>
	public class IndexKCls<K, T>
	{
		public IndexKCls()
		{
			this._Index = new Dictionary<K, Dictionary<int, T>>();
		}
		private Dictionary<K, Dictionary<int, T>> _Index;
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "{Index for Type:" + typeof(T).Name + "; KeyCount=" + this._Index.Count + "}";
		}
		/// <summary>
		/// Přidá do indexového pole nový pár hodnot Klíč/Hodnota
		/// </summary>
		/// <param name="key">Klíč indexu (Jde o index 1:N, toto je klíč nalevo)</param>
		/// <param name="value">Číslo datového údaje, na straně vpravo</param>
		/// <param name="data">Datový údaj</param>
		public void Add(K key, int value, T data)
		{
			Dictionary<int, T> listValues;
			if (!this._Index.TryGetValue(key, out listValues))
			{
				listValues = new Dictionary<int, T>();
				this._Index.Add(key, listValues);
			}
			if (!listValues.ContainsKey(value))
				listValues.Add(value, data);
		}
		/// <summary>
		/// Odebere z indexového pole všechny záznamy pro daný klíč (N záznamů, z indexu typu 1:N)
		/// </summary>
		/// <param name="key"></param>
		public void RemoveKey(K key)
		{
			if (this._Index.ContainsKey(key))
				this._Index.Remove(key);
		}
		/// <summary>
		/// Odebere z indexového pole určité záznamy (value) pro daný klíč (key). Jeden záznam ze strany N (napravo), indexu 1:N
		/// Neodebírá tedy všechny záznamy daného klíče, ale jen ty položky, které mají odpovídající Value.
		/// </summary>
		/// <param name="key"></param>
		public void RemoveItem(K key, int value)
		{
			Dictionary<int, T> listValues;
			if (this._Index.TryGetValue(key, out listValues))
			{
				if (listValues != null && listValues.ContainsKey(value))
					listValues.Remove(value);
			}
		}
		/// <summary>
		/// Vyprázdnění indexu
		/// </summary>
		public void Clear()
		{
			this._Index.Clear();
		}
		/// <summary>
		/// Najde a vrátí seznam hodnot (zadané jako value do metody Add)
		/// Pokud nenajde záznam pro hledaný klíč, vrátí prázdný seznam. Nevrací null.
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public List<int> GetValues(K key)
		{
			Dictionary<int, T> listValues;
			if (!this._Index.TryGetValue(key, out listValues))
			{
				listValues = new Dictionary<int, T>();
			}
			return new List<int>(listValues.Keys);
		}
		/// <summary>
		/// Najde a vrátí seznam hodnot (zadané jako value do metody Add).
		/// Pokud nenajde záznam pro hledaný klíč, vrátí prázdný seznam. Nevrací null.
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public List<T> GetData(K key)
		{
			Dictionary<int, T> listValues;
			if (!this._Index.TryGetValue(key, out listValues))
			{
				listValues = new Dictionary<int, T>();
			}
			return new List<T>(listValues.Values);
		}
	}
	#endregion
	#region CLASS IndexIntCls : jednoduchá podpora pro indexování dat typu 1:N <int, Dictionary<int, T>>
	/// <summary>
	/// IndexIntCls : jednoduchá podpora pro indexování dat typu 1:N &lt;int, Dictionary&lt;int, T&gt;&gt;
	/// </summary>
	public class IndexIntCls<T> : IndexKCls<Int32, T>
	{ }
	#endregion
	#region CLASS IntRange
	/// <summary>
	/// Rozmezí dvou hodnot Int32 včetně příznaku, zda jsou/nejsou naplněny
	/// </summary>
	internal class IntRange
	{
		#region KONSTRUKCE
		/// <summary> { get; }
		/// Dolní hodnota rozmezí
		/// </summary>
		public int LowValue { get { return _LowValue; } }
		private int _LowValue;
		/// <summary> { get; }
		/// Horní hodnota rozmezí
		/// </summary>
		public int HighValue { get { return _HighValue; } }
		private int _HighValue;
		/// <summary>
		/// Příznak, že tento objekt obsahuje prázdná data.
		/// </summary>
		/// <returns></returns>
		public bool IsEmpty { get { return (!this._IsFilled); } }
		/// <summary> { get; }
		/// Příznak, že rozmezí je již naplněno (buď konstruktorem s předanou hodnotou, anebo metodou StoreMinMax())
		/// </summary>
		public bool IsFilled { get { return _IsFilled; } }
		private bool _IsFilled;
		/// <summary>
		/// Implicitní konstruktor, objekt není naplněn
		/// </summary>
		public IntRange()
		{
			_LowValue = 0;
			_HighValue = 0;
			_IsFilled = false;
		}
		/// <summary>
		/// Explicitní konstruktor, objekt je naplněn hodnotami z parametrů
		/// </summary>
		/// <param name="lowValue"></param>
		/// <param name="highValue"></param>
		public IntRange(int lowValue, int highValue)
		{
			_LowValue = lowValue;
			_HighValue = highValue;
			_IsFilled = true;
		}
		/// <summary>
		/// Obsahuje prázdnou hodnotu (nevyplněnou)
		/// </summary>
		public static IntRange Empty { get { return new IntRange(); } }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "{" + (IsFilled ? (LowValue.ToString() + "÷" + HighValue.ToString()) : ("Empty")) + "}";
		}
		#endregion
		#region PLNĚNÍ : metoda StoreMinMax()
		/// <summary>
		/// Vložení hodnoty, zaznamená se případné rozšíření intervalu Low nebo HighValue, vždy se zaznamená IsFilled = true
		/// </summary>
		/// <param name="value"></param>
		public void StoreMinMax(int value)
		{
			if (!IsFilled)
			{
				_LowValue = value;
				_HighValue = value;
				_IsFilled = true;
			}
			else
			{
				if (value < _LowValue) _LowValue = value;
				if (value > _HighValue) _HighValue = value;
			}
		}
		/// <summary>
		/// Vrátí true, pokud hodnota (value) je v tomto rozsahu. Vrátí false, pokud tento rozsah není naplněn.
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		internal bool IsValueWithin(int value)
		{
			if (!IsFilled) return false;
			return (value >= LowValue && value <= HighValue);
		}
		#endregion
		#region EQUALS
		/// <summary>
		/// Equals() - pro použití GID v Hashtabulkách
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public override bool Equals(object obj)
		{
			if (!(obj is IntRange)) return false;
			return (IntRange._IsEqual(this, (IntRange)obj));
		}
		/// <summary>
		/// Porovnání dvou instancí této struktury, zda obsahují shodná data
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		private static bool _IsEqual(IntRange a, IntRange b)
		{
			return (a._LowValue == b._LowValue && a._HighValue == b._HighValue);
		}
		#endregion
		#region OPERÁTORY ==, !=, +, *
		/// <summary>
		/// Operátor "je rovno"
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator ==(IntRange a, IntRange b)
		{
			return IntRange._IsEqual(a, b);
		}
		/// <summary>
		/// Operátor "není rovno"
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator !=(IntRange a, IntRange b)
		{
			return (!IntRange._IsEqual(a, b));
		}
		/// <summary>
		/// Operátor "plus" = sčítání dvou intervalů = souhrn, sjednocení
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static IntRange operator +(IntRange a, IntRange b)
		{
			if (a.IsEmpty) return b;
			if (b.IsEmpty) return a;
			return new IntRange((a._LowValue < b._LowValue ? a._LowValue : b._LowValue), (a._HighValue > b._HighValue ? a._HighValue : b._HighValue));
		}
		/// <summary>
		/// Operátor "KRÁT" = násobení dvou intervalů = součin, průnik
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static IntRange operator *(IntRange a, IntRange b)
		{
			if (a.IsEmpty) return IntRange.Empty;
			if (b.IsEmpty) return IntRange.Empty;

			int low = (a._LowValue > b._LowValue ? a._LowValue : b._LowValue);       // Max(Low)
			int high = (a._HighValue < b._HighValue ? a._HighValue : b._HighValue);  // Min(High)
			if (low > high) return IntRange.Empty;
			return new IntRange(low, high);
		}
		#endregion
		#region ČTENÍ ROZSAHU VE FORMĚ POLE HODNOT
		/// <summary>
		/// Obsahuje (vygeneruje a vrátí) soupis hodnot v tomto rozsahu, ve formě listu.
		/// List je v pořadí od LowValue do HighValue, včetně obou krajních hodnot.
		/// </summary>
		public List<int> ListOfValuesAsc
		{
			get
			{
				if (!IsFilled) return null;
				List<int> result = new List<int>();
				for (int v = LowValue; v <= HighValue; v++)
					result.Add(v);
				return result;
			}
		}
		/// <summary>
		/// Obsahuje (vygeneruje a vrátí) soupis hodnot v tomto rozsahu, ve formě listu.
		/// List je v pořadí od HighValue do LowValue, včetně obou krajních hodnot.
		/// </summary>
		public List<int> ListOfValuesDesc
		{
			get
			{
				if (!IsFilled) return null;
				List<int> result = new List<int>();
				for (int v = HighValue; v >= LowValue; v--)
					result.Add(v);
				return result;
			}
		}
		#endregion
		#region DETEKTORY
		/// <summary>
		/// Obsahuje toto rozmezí danou hodnotu?
		/// Pokud je toto rozmezí neprázdné, a daná hodnota je uvnitř včetně mezních hranic, pak ano.
		/// Pokud je mimo, anebo toto rozmezí je reverzní (Low je větší než High), pak neobsahuje.
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool ContainValue(int value)
		{
			if (this.IsEmpty) return false;
			if (this.LowValue > this.HighValue) return false;
			return (value >= this.LowValue && value <= this.HighValue);
		}
		#endregion
	}
	#endregion
	#region STRUCT StockUnit : (obsahuje číslo skladu a číslo plánovací jednotky = klíč položky v rámci plánu, a základní metody pro jeho zpracování)
	/// <summary>
	/// Struktura, která obsahuje číslo skladu a číslo plánovací jednotky.
	/// Identifikuje tak jednu položku zásob.
	/// </summary>
	public struct StockUnit : IComparable<StockUnit>
	{
		#region ZÁKLADNÍ KONSTRUKCE (Konstruktor, Empty, IsEmpty, ToString)
		/// <summary>
		/// Číslo skladu
		/// </summary>
		public int StockMrp;
		/// <summary>
		/// Číslo plánovací jednotky
		/// </summary>
		public int PlanUnitS;
		/// <summary>
		/// Konstruktor
		/// </summary>
		/// <param name="stockMrp">Hodnota StockMrp = číslo MRP skladu (na tento sklad se plánuje)</param>
		/// <param name="planUnitS">Hodnota PlanUnitS = plánovací jednotka</param>
		public StockUnit(int stockMrp, int planUnitS)
		{
			this.StockMrp = stockMrp;
			this.PlanUnitS = planUnitS;
		}
		/// <summary>
		/// Konstruktor
		/// </summary>
		/// <param name="cSu">Sloučený identifikátor 64 bitů (StockMrp v horních 4 Bytech, PlanUnitS v dolních 4 bytech)</param>
		public StockUnit(long cSu)
		{
			this.StockMrp = 0;
			this.PlanUnitS = 0;
			this.CSu = cSu;
		}
		/// <summary>
		/// Obsahuje prázdné StockUnit
		/// </summary>
		public static StockUnit Empty { get { return new StockUnit(0, 0); } }
		/// <summary>
		/// Příznak, že tento objekt obsahuje prázdná data.
		/// </summary>
		public bool IsEmpty { get { return (this.StockMrp == 0 && this.PlanUnitS == 0); } }
		/// <summary>
		/// Příznak, že tento objekt obsahuje neprázdná data.
		/// </summary>
		public bool NotEmpty { get { return (this.StockMrp != 0 || this.PlanUnitS != 0); } }
		/// <summary>
		/// Obsahuje LONG sloučený identifikátor 64 bitů (StockMrp v horních 4 Bytech, PlanUnitS v dolních 4 bytech)
		/// </summary>
		public long CSu
		{
			get
			{
				long stockMrp = (long)this.StockMrp << 32;
				long planUnitS = (long)this.PlanUnitS;
				return (stockMrp | planUnitS);
			}
			set
			{
				this.StockMrp = (int)((value >> 32) & Int32.MaxValue);
				this.PlanUnitS = (int)(value & Int32.MaxValue);
			}
		}
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "[Stock=" + this.StockMrp.ToString() + "; PlanUnitS=" + this.PlanUnitS.ToString() + "]";
		}
		#endregion
		#region COMPARE (Hashcode, Equals, operator ==, !=, IComparable)
		/// <summary>
		/// GetHashCode() - pro použití StockUnit v Hashtabulkách
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode()
		{
			// Hashcode pro 2 hodnoty int vrací bit-XOR :
			return StockMrp ^ PlanUnitS;
		}
		/// <summary>
		/// Equals() - pro použití StockUnit v Hashtabulkách
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public override bool Equals(object obj)
		{
			if (!(obj is StockUnit)) return false;
			return (StockUnit._IsEqual(this, (StockUnit)obj));
		}
		/// <summary>
		/// Operátor "je rovno"
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator ==(StockUnit a, StockUnit b)
		{
			return StockUnit._IsEqual(a, b);
		}
		/// <summary>
		/// Operátor "není rovno"
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator !=(StockUnit a, StockUnit b)
		{
			return (!StockUnit._IsEqual(a, b));
		}
		/// <summary>
		/// Porovnání dvou instancí této struktury, zda obsahují shodná data
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		private static bool _IsEqual(StockUnit a, StockUnit b)
		{
			return (a.StockMrp == b.StockMrp && a.PlanUnitS == b.PlanUnitS);
		}
		/// <summary>
		/// Porovnání dvou instancí této struktury, zda obsahují shodná data
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		private static int _Compare(StockUnit a, StockUnit b)
		{
			if (a.StockMrp != b.StockMrp) return (a.StockMrp.CompareTo(b.StockMrp));
			return a.PlanUnitS.CompareTo(b.PlanUnitS);
		}
		#region IComparable<StockUnit> Members

		int IComparable<StockUnit>.CompareTo(StockUnit other)
		{
			return StockUnit._Compare(this, other);
		}

		#endregion
		#endregion
	}
	#endregion
	#region KONSTANTY
	/// <summary>
	/// KONSTANTY PLÁNOVACÍHO PROCESU
	/// </summary>
	public class Constants
	{
		/// <summary>
		/// Dočasné číslo třídy pro TASK = 0x10001
		/// </summary>
		public const int ClassNumberTask = 0x10001;
		/// <summary>
		/// Dočasné číslo třídy pro WorkPass = 0x10002
		/// </summary>
		public const int ClassNumberPass = 0x10002;
		/// <summary>
		/// Dočasné číslo třídy pro WorkTime = 0x10003
		/// </summary>
		public const int ClassNumberTime = 0x10003;
		/// <summary>
		/// Dočasné číslo třídy pro WorkUnit = 0x10004
		/// </summary>
		public const int ClassNumberWork = 0x10004;
		/// <summary>
		/// Dočasné číslo třídy pro JOB = 0x10005
		/// </summary>
		public const int ClassNumberJob = 0x10005;
		/// <summary>
		/// Dočasné číslo třídy pro AXIS = 0x10006
		/// </summary>
		public const int ClassNumberAxis = 0x10006;
		/// <summary>
		/// Dočasné číslo třídy pro paměťové záznamy LEVEL = 0x10007
		/// </summary>
		public const int ClassNumberLevel = 0x10007;
		/// <summary>
		/// Dočasné číslo třídy pro paměťové záznamy DESK = 0x10008
		/// </summary>
		public const int ClassNumberDesk = 0x10008;
		/// <summary>
		/// Dočasné číslo třídy pro podřízené řádky AXIS = 0x10009
		/// </summary>
		public const int ClassNumberAxisSubRow = 0x10009;
        /// <summary>
        /// Náhradní číslo třídy pro data Obecný zdroj kapacit = 0x1000A
        /// </summary>
        public const int ClassNumberCapacitySource = 0x1000A;
        /// <summary>
		/// Pracovní číslo třídy Výstup z výroby = 0x10040.
		/// Toto číslo se používá jako číslo třídy GIDu, který je navázán jako cíl vztahu, kdy výsledek výroby vystupuje z plánovací osy.
		/// Typ vztahu je PlanningItemRelationType.AxisOutput.
		/// Výsledek takové výroby = a) výdej do poptávky, anebo b) výroba na sklad (výrobní příkaz, jehož finál se nikde nespotřebovává).
        /// Záznamy osy S uvedené v tomto vztahu na straně Prev se zobrazují v grafu Gantt osy S.
		/// </summary>
		public const int ClassNumberOutput = 0x10040;
		/// <summary>
		/// Číslo třídy Obecná poptávka = 214
		/// </summary>
		public const int ClassNumberEnquiry = 214;
        /// <summary>
        /// Číslo třídy Pořadač = 9
        /// </summary>
        public const int ClassNumberPoradac = 9;
        /// <summary>
		/// Číslo třídy Organizace = 12
		/// </summary>
		public const int ClassNumberOrganizace = 12;
		/// <summary>
		/// Číslo třídy Obecný subjekt = 13
		/// </summary>
		public const int ClassNumberObecnySubjekt = 13;
        /// <summary>
        /// Číslo třídy Obecná objednávka = 213
        /// </summary>
        public const int ClassNumberObecnaObjednavka = 213;
        /// <summary>
        /// Číslo třídy Obecná poptávka = 214
        /// </summary>
        public const int ClassNumberObecnaPoptavka = 214;
        /// <summary>
        /// Číslo třídy Obecná potvrzená poptávka = 802
        /// </summary>
        public const int ClassNumberObecnaPotvrzenaPoptavka = 802;
        /// <summary>
        /// Číslo třídy K modifikace STPV = 1161
        /// </summary>
        public const int ClassNumberAStructureMod = 1161;

        /// <summary>
        /// Číslo extended vztahu do stromu tříd: "WorkUnitCls --» PlanUnitCCls" (0x10100 = 65 792)
        /// </summary>
        public const int RelationExtNumber_WorkUnit_PlanUnitC = 0x10100;
        /// <summary>
        /// Číslo extended vztahu do stromu tříd: "WorkUnitCls --» PlanUnitSAxis" (0x10101 = 65 793)
        /// </summary>
        public const int RelationExtNumber_WorkUnit_PlanUnitSAxis = 0x10101;
        /// <summary>
        /// Číslo extended vztahu do stromu tříd: "WorkUnitCls --» PlanUnitCTask" (0x10102 = 65 794)
        /// </summary>
        public const int RelationExtNumber_WorkUnit_PlanUnitCTask = 0x10102;
        /// <summary>
        /// Číslo extended vztahu do stromu tříd: "WorkUnitCls --» CapacityLevel" (0x10103 = 65 795)
        /// </summary>
        public const int RelationExtNumber_WorkUnit_CapacityLevel = 0x10103;
        /// <summary>
        /// Číslo extended vztahu do stromu tříd: "PlanUnitSAxis --» Obecná poptávka položka" (0x10104 = 65 796)
        /// </summary>
        public const int RelationExtNumber_AxisS_EnquiryEntry = 0x10104;
		/// <summary>
		/// Číslo extended vztahu do stromu tříd: "PlanningClass --» Finální záznam osy S" (0x10105 = 65 797)
		/// </summary>
		public const int RelationExtNumber_AnyPlan_FinalAxisS = 0x10105;
		/// <summary>
        /// Číslo extended vztahu do stromu tříd: "Pořadačová třída --» Pořadač" (0x10201 = 66 000)
        /// </summary>
        public const int RelationExtNumber_AnyClass_Folder = 0x101d0;

		/// <summary>
		/// Číslo funkce Plánovací proces = 5591
		/// </summary>
		public const int FunctionNumberPlanningProcess = 5591;
		/// <summary>
		/// Hodnota používaná jako TAG pro grafy, které zakládá Planning.Process
		/// </summary>
		public const int PlanningGraphTag = 16180523;

        /// <summary>
        /// Konstanta do Trace - do sloupce Keyword pro označení bloku aplikačního kódu Scheduler
        /// </summary>
        public const string TraceKeyWordAplScheduler = "App.Scheduler";
        /// <summary>
        /// Konstanta do Trace - do sloupce Type pro označení bloku aplikačního kódu AxisHeap
        /// </summary>
        public const string TraceTypeAxis = "AxisHeap";
        /// <summary>
        /// Konstanta do Trace - do sloupce Type pro označení bloku aplikačního kódu Capacity
        /// </summary>
        public const string TraceTypeCapacity = "Capacity";
        /// <summary>
        /// Konstanta do Trace - do sloupce Type pro označení bloku aplikačního kódu Material
        /// </summary>
        public const string TraceTypeMaterial = "Material";
        /// <summary>
        /// Konstanta do Trace - do sloupce Type pro označení bloku aplikačního kódu Product
        /// </summary>
        public const string TraceTypeProduct = "Product";
        /// <summary>
        /// Konstanta do Trace - do sloupce Type pro označení bloku aplikačního kódu TpvDoc
        /// </summary>
        public const string TraceTypeTpvDoc = "TpvDoc";
    }
	#endregion
	#region INTERFACE IRecordNumber
	/// <summary>
	/// Interface, který předepisuje přítomnost property int RecordNumber { get; set; }, nic dalšího
	/// </summary>
	public interface IRecordNumber
	{
		/// <summary>
		/// Číslo databázového záznamu
		/// </summary>
		int RecordNumber { get; set; }
	}
	#endregion
}
